import json
import re
from django.conf import settings
from django.contrib.auth.mixins import LoginRequiredMixin
from django_redis import get_redis_connection
from django.http import JsonResponse
from django.views import View
from django.middleware.csrf import get_token
from django.contrib.auth import logout
from django.contrib.auth import authenticate, login
from carts.utils import CartHelper
from users.models import User
from users.models import Address

# 判断用户名是否重复
# GET /usernames/(?P<username>[a-zA-Z0-9_-]{5,20})/count/
class UsernameCountView(View):
    def get(self, request, username):
        """判断注册用户名是否重复"""
        # ① 查询数据库判断username是否存在
        try:
            count = User.objects.filter(username=username).count()
        except Exception as e:
            return JsonResponse({'code': 400,
                                 'message': '操作数据库失败!'})

        # ② 返回响应数据
        return JsonResponse({'code': 0,
                             'message': 'OK',
                             'count': count})

# 判断注册手机号是否重复
class MobileCountView(View):
    def get(self, request, mobile):
        """判断注册手机号是否重复"""
        # ① 查询数据库判断mobile是否存在
        try:
            count = User.objects.filter(mobile=mobile).count()
        except Exception as e:
            return JsonResponse({'code': 400,
                                 'message': '操作数据库失败!'})

        # ② 返回响应数据
        return JsonResponse({'code': 0,
                             'message': 'OK',
                             'count': count})

# 注册用户名信息保存
# POST /register/
class RegisterView(View):
    def post(self, request):
        """注册用户信息保存"""
        # ① 获取参数并进行校验
        req_data = json.loads(request.body.decode())
        username = req_data.get('username')
        password = req_data.get('password')
        password2 = req_data.get('password2')
        mobile = req_data.get('mobile')
        allow = req_data.get('allow')
        sms_code = req_data.get('sms_code')

        if not all([username, password, password2, mobile, allow, sms_code]):
            return JsonResponse({'code': 400,
                                 'message': '缺少必传参数'})

        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return JsonResponse({'code': 400,
                                 'message': 'username格式错误'})

        if not re.match(r'^[a-zA-Z0-9]{8,20}$', password):
            return JsonResponse({'code': 400,
                                 'message': 'password格式错误'})

        if password != password2:
            return JsonResponse({'code': 400,
                                 'message': '两次密码不一致'})

        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': 400,
                                 'message': '手机号格式错误'})

        if not allow:
            return JsonResponse({'code': 400,
                                 'message': '请同意协议!'})

        # 短信验证码检验
        redis_conn = get_redis_connection('verify_code')
        sms_code_redis = redis_conn.get('sms_%s' % mobile)

        if not sms_code_redis:
            return JsonResponse({'code': 400,
                                 'message': '短信验证码过期'})

        if sms_code != sms_code_redis:
            return JsonResponse({'code': 400,
                                 'message': '短信验证码错误'})

        # ② 保存新增用户数据到数据库
        try:
            user = User.objects.create_user(username=username,
                                            password=password,
                                            mobile=mobile)
        except Exception as e:
            return JsonResponse({'code': 400,
                                 'message': '数据库保存错误'})
        # 保存登录状态信息
        from django.contrib.auth import login
        login(request, user)

        # ③ 返回响应
        response = JsonResponse({'code': 0,
                                 'message': 'OK'})

        # 设置 cookie 保存 username 用户名
        response.set_cookie('username',
                            user.username,
                            max_age=3600 * 24 * 14)

        # 增加代码：合并购物车数据
        cart_helper = CartHelper(request, response)
        cart_helper.merge_cookie_cart_to_redis()

        return response

# 获取csrf_token的值
# GET /csrf_token/
class CSRFTokenView(View):
    def get(self, request):
        """获取csrf_token的值"""
        # ① 生成csrf_token的值
        csrf_token = get_token(request)

        # ② 将csrf_token的值返回
        return JsonResponse({'code': 0,
                             'message': 'OK',
                             'csrf_token': csrf_token})

# 用户登录
# POST /login/
class LoginView(View):
    def post(self, request):
        """用户登录"""
        # ① 获取参数并进行校验(参数完整性、用户名密码是否正确)
        req_data = json.loads(request.body.decode())

        username = req_data.get('username')
        password = req_data.get('password')
        remember = req_data.get('remember')

        if not all([username, password]):
            return JsonResponse({'code': 400,
                                 'message': '缺少必传参数'})

        # 判断客户端传递的 username 参数是否符合手机号格式
        import re
        if re.match(r'^1[3-9]\d{9}$', username):
            User.USERNAME_FIELD = 'mobile'
        else:
            User.USERNAME_FIELD = 'username'

        # 账户和密码是否正确
        user = authenticate(username=username, password=password)

        if user is None:
            return JsonResponse({'code': 400,
                                 'message': '用户名或密码错误'})

        # ② 保存登录用户的状态信息
        login(request, user)

        if not remember:
            # 如果未选择记住登录，浏览器关闭即失效
            request.session.set_expiry(0)

            # ③ 返回响应，登录成功
            response = JsonResponse({'code': 0,
                                     'message': 'OK'})

            # 设置 cookie 保存 username 用户名
            response.set_cookie('username',
                                user.username,
                                max_age=3600 * 24 * 14)

            # 增加代码：合并购物车数据
            cart_helper = CartHelper(request, response)
            cart_helper.merge_cookie_cart_to_redis()

            return response

# 退出登录
# DELETE /logout/
class LogoutView(View):
    def delete(self, request):
        """退出登录"""
        # ① 请求登录用户的session信息
        logout(request)

        # ② 删除cookie中的username
        response = JsonResponse({'code': 0,
                                 'message': 'ok'})

        response.delete_cookie('username')

        # ③ 返回响应
        return response

# 获取登录用户个人信息
# GET /user/
class UserInfoView(LoginRequiredMixin,View):
    def get(self, request):
        """获取登录用户个人信息"""
        # 判断用户是否登录
        if not request.user.is_authenticated:
            return JsonResponse({
                'code':400,
                'message': '用户未登录！'
            })
        # ① 获取登录用户对象
        user = request.user

        # ② 返回响应数据
        info = {
            'username': user.username,
            'mobile': user.mobile,
            'email': user.email,
            'email_active': user.email_active
        }

        return JsonResponse({'code': 0,
                             'message': 'OK',
                             'user': info})

# 设置个人邮箱
# PUT /user/email/
class UserEmailView(LoginRequiredMixin, View):
    def put(self, request):
        """设置用户的个人邮箱"""
        # ① 获取参数并进行校验
        req_data = json.loads(request.body.decode())

        email = req_data.get('email')

        if not email:
            return JsonResponse({'code': 400,
                                 'message': '缺少email参数'})

        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return JsonResponse({'code': 400,
                                 'message': '参数email有误'})

        # ② 保存用户的个人邮箱设置
        user = request.user
        try:
            user.email = email
            user.save()
        except Exception as e:
            return JsonResponse({'code': 400,
                                 'message': '邮箱设置失败'})

        # # 给用户的邮箱发送一封验证
        # html_message = '<a href="#">点击链接激活您的邮箱</a>'
        #
        # from django.core.mail import send_mail
        # send_mail('美多商城验证邮件',
        #           '',
        #           settings.EMAIL_FROM,
        #           [email],
        #           html_message=html_message
        #           )

        # Celery 异步发送邮箱验证邮件
        from celery_tasks.email.tasks import send_verify_email
        verify_url = user.generate_verify_email_url()
        # 发出邮件发送的任务消息
        send_verify_email.delay(email, verify_url)

        # ③ 返回响应
        return JsonResponse({'code': 0,
                             'message': 'OK'})

# 用户邮箱验证
# PUT /emails/verification/
class EmailVerifyView(View):
    def put(self, request):
        """用户邮箱验证"""
        # ① 获取加密的用户token并进行校验
        token = request.GET.get('token')

        if not token:
            return JsonResponse({'code': 400,
                                 'message': '缺少token参数'})

        # 对用户的信息进行解密
        user = User.check_verify_email_token(token)

        if user is None:
            return JsonResponse({'code': 400,
                                 'message': 'token信息有误'})

        # ② 设置对应用户的邮箱验证标记为已验证
        try:
            user.email_active = True
            user.save()
        except Exception as e:
            return JsonResponse({'code': 400,
                                 'message': '验证邮箱失败'})


        # ③ 返回响应
        return JsonResponse({'code': 0,
                             'message': 'OK'})


# 用户收货地址新增
# POST /addresses/
class AddressView(LoginRequiredMixin, View):
    def post(self, request):
        """用户收货地址新增"""
        # ① 判断当前用户的收货地址是否超过上限
        try:
            count = Address.objects.filter(user=request.user, is_delete=False).count()
        except Exception:
            return JsonResponse({'code': 400,
                                 'message': '获取地址数据出错'})

        if count >= 20:
            return JsonResponse({'code': 400,
                                 'message': '收货地址超过上限'})

        # ② 接收参数并进行数据校验
        req_data = json.loads(request.body)

        title = req_data.get('title')
        receiver = req_data.get('receiver')
        province_id = req_data.get('province_id')
        city_id = req_data.get('city_id')
        district_id = req_data.get('district_id')
        place = req_data.get('place')
        mobile = req_data.get('mobile')
        phone = req_data.get('phone')
        email = req_data.get('email')

        if not all([title, receiver, province_id, city_id, district_id, place, mobile]):
            return JsonResponse({'code': 400,
                                 'message': '缺少必传参数'})

        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': 400,
                                 'message': '参数mobile有误'})

        if phone:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', phone):
                return JsonResponse({'code': 400,
                                     'message': '参数phone有误'})
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return JsonResponse({'code': 400,
                                     'message': '参数email有误'})

        # ③ 保存收货地址数据
        try:
            address = Address.objects.create(user=request.user, **req_data)

            # 设置默认收货地址
            if not request.user.default_address:
                request.user.default_address = address
                request.user.save()
        except Exception:
            return JsonResponse({'code': 400,
                                 'message': '新增地址保存失败'})

        # ④ 返回响应
        address_data = {
            'id': address.id,
            'title': address.title,
            'receiver': address.receiver,
            'province': address.province.name,
            'city': address.city.name,
            'district': address.district.name,
            'place': address.place,
            'mobile': address.mobile,
            'phone': address.phone,
            'email': address.email
        }
        return JsonResponse({'code': 0,
                             'message': 'OK',
                             'address': address_data})
    # GET/addresses/
    def get(self, request):
        '''登录用户地址数据获取'''
        default_address = request.user.default_address_id
        try:
            address = Address.objects.filter(user=request.user, is_delete= False)
        except Exception:
            return JsonResponse({
                'code': 400,
                'message':'获取登录地址出错'
            })
        list1 = []
        for lala in address:
            data = {
                'id': lala.id,
                'title': lala.title,
                'receiver': lala.receiver,
                "province": lala.province.name,
                "city": lala.city.name,
                "district": lala.district.name,
                "province_id": lala.province_id,
                "city_id": lala.city_id,
                "district_id": lala.district_id,
                "place": lala.place,
                "mobile": lala.mobile,
                "phone": lala.phone,
                "email": lala.email
            }
            list1.append(data)

        return JsonResponse({'code':0,
                             'message':'OK',
                             'default_address_id': default_address,
                             'addresses': list1})

# 收货地址修改
# PUT/addresses/(?P<address_id>\d+)/
class AdderssesPutView(LoginRequiredMixin, View):
    def put(self, request, address_id):
        '''收货地址修改'''
        try:
            address = Address.objects.get(user=request.user, id=address_id)
        except Exception:
            return JsonResponse({
                'code': 400,
                'message': '修改地址出错'
            })
        request_json = json.loads(request.body)
        # 获取请求参数并进行校验
        title = request_json.get('title')
        receiver = request_json.get('receiver')
        province_id = request_json.get('province_id')
        city_id = request_json.get('city_id')
        district_id = request_json.get('district_id')
        place = request_json.get('place')
        mobile = request_json.get('mobile')
        phone = request_json.get('phone')
        email = request_json.get('email')

        # 参数完整性
        if not all([title, receiver, province_id,
                    city_id, district_id, place, mobile]):
            return JsonResponse({'code': 400,
                                 'message': '缺少必传参数'})
        # 更新数据
        try:
            address.title = title
            address.receiver = receiver
            address.province_id = province_id
            address.city_id = city_id
            address.district_id = district_id
            address.place = place
            address.mobile = mobile
            address.phone = phone
            address.email = email
            address.save()
        except Exception as e:
            return JsonResponse({'code': 400,
                                 'message': '更新数据出错'})
        lala = Address.objects.get(user=request.user, id=address_id)

        return JsonResponse({
            'code':0,
            'message': 'OK',
            'address': {
                   'id': lala.id,
                'title': lala.title,
                'receiver': lala.receiver,
                "province": lala.province.name,
                "city": lala.city.name,
                "district": lala.district.name,
                "province_id": lala.province_id,
                "city_id": lala.city_id,
                "district_id": lala.district_id,
                "place": lala.place,
                "mobile": lala.mobile,
                "phone": lala.phone,
                "email": lala.email

            }})

    # 登录用户指定收货地址删除
    # API: DELETE / addresses / (?P < address_id > \d+) /
    def delete(self, request, address_id):
        '''删除指定地址'''
        try:
            address = Address.objects.get(user=request.user, id=address_id).delete()
        except Exception:
            return JsonResponse({
                'code': 400,
                'message': '地址未删除成功'
            })
        return JsonResponse({
            'code': 0,
            'message': 'OK'
        })


# PUT /addresses/(?P<address_id>\d+)/default/
class AddressesDefault(View):
    def put(self, request, address_id):
        '''登录用户默认收货地址设置'''
        address = Address.objects.get(id=address_id)

        try:
            # user = User.objects.get(id=address.user.id)
            request.user.default_address = address
            request.user.save()

        except Exception:
            return JsonResponse({'code': 400,
                                 'message': '设置失败'})
        else:
            return JsonResponse({'code': 0,

                                 'message': 'OK'})


# PUT /addresses/(?P<address_id>\d+)/title/
class AddressesId(LoginRequiredMixin, View):
    def put(self, request, address_id):
        '''登录用户指定收货地址标题'''
        request_json = json.loads(request.body)
        title = request_json.get('title')
        try:
            Address.objects.filter(user=request.user, id=address_id).update(title=title)
        except Exception:
            return JsonResponse({'code': 400,
                                 'message': '修改失败'})
        address = Address.objects.get(user=request.user, id=address_id)
        return JsonResponse({
            'code': 0,
            'message': 'OK'})


# PUT/password/
class PasswordView(LoginRequiredMixin, View):
    def put(self, request):
        '''修改登录用户的密码：
        ① 获取参数并进行校验(旧密码是否正确)
        ② 修改登录用户的密码
        ③ 返回响应，设置成功
        '''

        # ① 获取参数并进行校验(旧密码是否正确)
        req_data = json.loads(request.body)

        old_password = req_data.get('old_password')
        new_password = req_data.get('new_password')
        new_password2 = req_data.get('new_password2')

        if not all([old_password, new_password, new_password2]):
            return JsonResponse({'code': 400,
                                 'message': '缺少必传参数！'})

        if new_password != new_password2:
            return JsonResponse({'code': 400,
                                 'message': '密码不一致, 请重新输入'})
        # 获取登录用户
        user = request.user
        if not user.check_password(old_password):
            return JsonResponse({'code': 400,
                                 'message': '原始密码错误！'})

        # ② 修改登录用户的密码
        try:
            user.set_password(new_password)
            user.save()
        except Exception as e:
            return JsonResponse({'code': 400,
                                 'message': '密码设置出错！'})

        # ③ 返回响应， 设置成功
        return JsonResponse({'code':0,
                             'message': 'OK'})